#include "umCacheBuffer.h"
#include "umapi_os.h"
#include "umapi_libc.h"
#include "umlog.h"

typedef struct {
    UM_U8 *source;
    UM_S32 br;
    UM_S32 bw;
    UM_S32 btoRead;
    UM_S32 length;
	UM_HANDLE mutexHandle;
}S_CACHEBUFFER;

UM_VOID * createCache(UM_S32 size)
{
	S_CACHEBUFFER *pCache = (S_CACHEBUFFER*)umapi_malloc(sizeof(S_CACHEBUFFER));
	if(!pCache)
	{
		LOGS("malloc cachebuff fail");
		return UM_NULL;
	}
	pCache->source = umapi_malloc(size);
	if(!pCache->source)
	{
		LOGS("malloc cache buff fail");
		umapi_free(pCache);
		return UM_NULL;
	}
	pCache->br         = 0;
	pCache->bw         = 0;
	pCache->btoRead    = 0;
	pCache->length     = size;
	umapi_os_mutex_create("CACHE",UM_OS_MUTEX_ATTR_RECURSIVE_NP,&pCache->mutexHandle);
	return pCache;
}
UM_S32 destoryCache(UM_VOID * pCache)
{
	S_CACHEBUFFER *p = (S_CACHEBUFFER *)pCache;
	umapi_os_mutex_destroy(p->mutexHandle);
	umapi_free(p->source);
	umapi_free(p);
	return UM_SUCCESS;
}
UM_S32 clearCache(UM_VOID * pCache)
{
	S_CACHEBUFFER *p = (S_CACHEBUFFER *)pCache;
	umapi_os_mutex_lock(p->mutexHandle, -1);
	p->br         = 0;
	p->bw         = 0;
	p->btoRead    = 0;
	umapi_os_mutex_unlock(p->mutexHandle);
	return UM_SUCCESS;
}

UM_S32 writeCache(UM_VOID * pCache, UM_VOID *pBuffer, UM_S32 size)
{
	S_CACHEBUFFER *p = (S_CACHEBUFFER *)pCache;
	umapi_os_mutex_lock(p->mutexHandle, -1);
	UM_U32 len            = 0;
	UM_U32 ringBuf_bw     = p->bw;
	UM_U32 ringBuf_len    = p->length;
	UM_U8 *ringBuf_source = p->source;
	if( (ringBuf_bw + size) <= ringBuf_len)
	{
		memcpy(ringBuf_source + ringBuf_bw, pBuffer, size);
	}
	else
	{
		len = ringBuf_len - ringBuf_bw;
		memcpy(ringBuf_source + ringBuf_bw, pBuffer, len);
		memcpy(ringBuf_source, pBuffer + len, size - len);
	}

	p->bw = (p->bw + size) % ringBuf_len;
	p->btoRead += size;
	umapi_os_mutex_unlock(p->mutexHandle);
	return size;
}

UM_S32 readCache(UM_VOID * pCache, UM_VOID *pBuffer, UM_S32 *pSize)
{
	S_CACHEBUFFER *p = (S_CACHEBUFFER *)pCache;
	umapi_os_mutex_lock(p->mutexHandle, -1);
	UM_U32 len            = 0;
	UM_U32 ringBuf_br     = p->br;
	UM_U32 ringBuf_len    = p->length;
    UM_U8 *ringBuf_source = p->source;

	UM_S32 size = *pSize;
	if( (ringBuf_br + size ) <= ringBuf_len )
	{
		memcpy(pBuffer, ringBuf_source + ringBuf_br, size);
	}
	else
	{
		len = ringBuf_len - ringBuf_br;
		memcpy(pBuffer, ringBuf_source + ringBuf_br, len);
		memcpy(pBuffer + len, ringBuf_source, size - len);
	}

	p->br = (p->br + size) % ringBuf_len;
	p->btoRead -= size;
	*pSize = size;
	umapi_os_mutex_unlock(p->mutexHandle);
	return size;
}

UM_S32 getCacheLength(UM_VOID * pCache)
{
	S_CACHEBUFFER *p = (S_CACHEBUFFER *)pCache;
	return p->btoRead;
}
UM_S32 getCacheSize(UM_VOID * pCache)
{
	S_CACHEBUFFER *p = (S_CACHEBUFFER *)pCache;
	return p->length;
}

